package cn.tworice.upload.client.local;

import cn.tworice.common.util.StringUtils;
import cn.tworice.common.util.spring.ApplicationUtil;
import cn.tworice.upload.client.FileClient;
import cn.tworice.upload.client.FileClientProperties;
import cn.tworice.upload.service.FileEncryptionUtil;
import cn.tworice.upload.service.UploadUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Iterator;

/**
 * 本地文件客户端
 */
@Slf4j
public class LocalFileClient implements FileClient {

    private final UploadUtil uploadUtil;

    private final FileClientProperties properties;

    public LocalFileClient() {
        uploadUtil = ApplicationUtil.getApplicationContext().getBean(UploadUtil.class);
        properties = ApplicationUtil.getApplicationContext().getBean(FileClientProperties.class);
    }

    /**
     * 上传文件
     *
     * @param file 文件
     * @return 存储后的相对路径
     */
    @Override
    public String upload(MultipartFile file){
        String path = StringUtils.generateUuid() + uploadUtil.getFileExt(file);
        this.uploadFile(file, uploadUtil.getUploadPath() + path);
        return path;
    }

    @Override
    public String upload(byte[] fileBytes, String fileExt) throws IOException {
        String path = StringUtils.generateUuid() + "." + fileExt;
        return this.uploadToName(fileBytes, path);
    }

    @Override
    public String upload(BufferedImage image) throws IOException {
        String path = StringUtils.generateUuid() + ".jpg";
        File outputFile = new File(uploadUtil.getUploadPath() + path);
        outputFile.getParentFile().mkdirs();
        Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpeg");
        ImageWriter writer = writers.next();
        ImageWriteParam param = writer.getDefaultWriteParam();
        param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
        param.setCompressionQuality(1); // 设置压缩质量（0.0~1.0）
        try (ImageOutputStream outputStream = ImageIO.createImageOutputStream(outputFile)) {
            writer.setOutput(outputStream);
            writer.write(null, new IIOImage(image, null, null), param);
        }
        writer.dispose();
        return path;
    }

    @Override
    public String uploadToName(byte[] fileBytes, String fileName) throws IOException {
        if (fileBytes != null) {
            // 将字节数组写入到文件
            try (FileOutputStream fileOutputStream = new FileOutputStream(uploadUtil.getUploadPath() + fileName)) {
                fileOutputStream.write(fileBytes);
            }
            log.info("文件已保存到：" + uploadUtil.getUploadPath() + fileName);
        } else {
            throw new IOException("文件内容为空！");
        }
        return fileName;
    }

    /**
     * 上传文件到指定目录
     * @param file 文件
     * @param dir 目录
     * @return 存储后的相对路径
     */
    @Override
    public String uploadToPath(MultipartFile file, String dir) {
        String path = StringUtils.generateUuid() + dir + File.separator +uploadUtil.getFileExt(file);
        this.uploadFile(file, uploadUtil.getUploadPath() + path);
        return path;
    }

    /**
     * 删除文件
     * @param path 相对路径
     */
    @Override
    public void delete(String path) {
        Path filePath = Paths.get(this.getFinalPath(path));
        try {
            Files.delete(filePath);  // 删除文件
            log.debug("文件已删除："+uploadUtil.getUploadPath() + path);
        } catch (IOException e) {
            System.out.println("删除文件失败: " + e.getMessage());
        }
    }

    /**
     * 获取文件的字节数据
     * @param path 相对路径
     * @return
     * @throws Exception
     */
    @Override
    public byte[] getContent(String path) throws Exception {
        return Files.readAllBytes(Paths.get(this.getFinalPath(path)));
    }

    /**
     * 获取文件绝对路径
     * @param path 相对路径
     * @return 绝对路径
     */
    private String getFinalPath(String path) {
        return uploadUtil.getUploadPath() + path;
    }

    /**
     * 上传文件
     * @param file
     * @param path
     * @return
     */
    private void uploadFile(MultipartFile file, String path) {
        try {
            if (file == null || file.getOriginalFilename()==null) {
                return;
            }
            if(properties.getCryption()){ // 判断是否需要加密
                file = FileEncryptionUtil.encodeMultipartFileToBase64(file);
            }
            log.debug("试图上传文件至：" + path);
            file.transferTo(new File(path));
            log.debug("上传文件成功");
        }catch (Exception e){
            throw new RuntimeException("上传文件失败");
        }
    }
}
